/*
 *  Copyright (C) 2011 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.commons;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JPanel;
import org.balisunrise.annotation.IsEntityValid;
import org.balisunrise.annotation.PanelType;
import org.balisunrise.application.Application;
import org.balisunrise.builder.CommonFactory;
import org.balisunrise.builder.FactoryException;
import org.balisunrise.common.BindingGroup;
import org.balisunrise.common.Mode;
import org.balisunrise.common.VisualEntityType;
import org.balisunrise.common.events.AfterBindEvent;
import org.balisunrise.common.events.AfterUnbindEvent;
import org.balisunrise.common.listeners.EntityPanelListener;

/**
 *
 * @author glauco
 */
public class EntityPanel extends Layoutable
        implements org.balisunrise.common.EntityPanel<JPanel>{

    private Serializable entity;
    private PanelType type;
    private List<org.balisunrise.common.EntityPanel<JPanel>> associatedPanels;
    private BindingGroup bindingGroup;
    private List<EntityPanelListener> listeners;

    private static final String PROP_ENTITY = "entity";
    private static final String PROP_BINDINGGROUP = "bindingGroup";
    private static final String PROP_TYPE = "type";

    public EntityPanel() {
        associatedPanels =
                new ArrayList<org.balisunrise.common.EntityPanel<JPanel>>();
        listeners = new ArrayList<EntityPanelListener>();
        setVisualEntityType(VisualEntityType.ENTITY_PANEL);
    }

    @Override
    public Serializable getEntity() {
        return entity;
    }

    @Override
    public void setEntity(Serializable entity) {
        Serializable old = this.entity;
        this.entity = entity;
        changeSupport.firePropertyChange(PROP_ENTITY, old, entity);
    }

    @Override
    public PanelType getType() {
        return type;
    }

    public void setType(PanelType type) {
        PanelType oldType = this.type;
        this.type = type;
        changeSupport.firePropertyChange(PROP_TYPE, oldType, type);
    }

    @Override
    public List<org.balisunrise.common.EntityPanel<JPanel>>
            getAssociatedPanels() {
        return associatedPanels;
    }

    public void setAssociatedPanels(
            List<org.balisunrise.common.EntityPanel<JPanel>>
            associatedPanels) {
        this.associatedPanels = associatedPanels;
    }

    @Override
    public boolean isEntityValid() {
        for (Method method : getEntity().getClass().getMethods()) {
            if (method.isAnnotationPresent(IsEntityValid.class) &&
                    method.getParameterTypes().length == 0 &&
                    method.getReturnType().equals(Boolean.class)){
                try {
                    return (Boolean) method.invoke(getEntity());
                } catch (Exception ex) {
                    Application.get().getLogger().log(Level.SEVERE,
                            "EntityPanel não pode executar IsEntityValid", ex);
                }
            }
        }
        return true;
    }

    /**
     * Realiza o Vínculo entre os componentes visuais e os atributos da entidade.
     */
    @Override
    public void bind() {
        if (bindingGroup != null)
            bindingGroup.bind();
        for (org.balisunrise.common.EntityPanel<JPanel> ap : associatedPanels) {
            ap.bind();
        }

        try{
            AfterBindEvent evt = CommonFactory.getFactory()
                    .createAfterBindEvent(this);
            for (EntityPanelListener epl : listeners) {
                epl.afterBind(evt);
            }
            getOwner().actionPerformed(evt);
        }catch(FactoryException ex){
            Application.get().getLogger().log(Level.SEVERE,
                    "EntityPanel não pode criar AfterBindEvent", ex);
        }
    }

    /**
     * Desfaz o Vínculo entre os componentes visuais e os atributos da entidade.
     */
    @Override
    public void unBind() {
        if (bindingGroup != null)
            bindingGroup.unbind();
        for (org.balisunrise.common.EntityPanel<JPanel> ap : associatedPanels) {
            ap.unBind();
        }

        try{
            AfterUnbindEvent evt = CommonFactory.getFactory()
                    .createAfterUnbindEvent(this);
            for (EntityPanelListener epl : listeners) {
                epl.afterUnbind(evt);
            }
            getOwner().actionPerformed(evt);
        }catch(FactoryException ex){
            Application.get().getLogger().log(Level.SEVERE,
                    "EntityPanel não pode criar AfterUnbindEvent", ex);
        }
    }

    @Override
    public void setBindingGroup(BindingGroup bindingGroup) {
        if (this.bindingGroup != null)
            this.unBind();

        if(!associatedPanels.isEmpty()){
            for (org.balisunrise.common.EntityPanel<JPanel> ap : associatedPanels) {
                ap.setBindingGroup(bindingGroup);
            }
        }else{
            createBindings(bindingGroup, this, PROP_ENTITY);
        }

        BindingGroup oldBindingGroup = this.bindingGroup;
        this.bindingGroup = bindingGroup;
        changeSupport.firePropertyChange(PROP_BINDINGGROUP,
                oldBindingGroup, bindingGroup);
    }

    @Override
    public void addEntityPanelListener(EntityPanelListener el) {
        listeners.add(el);
    }

    @Override
    public boolean removeEntityPanelListener(EntityPanelListener el) {
        return listeners.remove(el);
    }

    @Override
    public EntityPanelListener[] getEntityPanelListeners() {
        return listeners.toArray(new EntityPanelListener[]{});
    }

    @Override
    public void setMode(int mode) {
        switch (mode) {
            case Mode.DELETE:
                getVisualRepresentation().setEnabled(false);
                break;
            default:
                getVisualRepresentation().setEnabled(true);
        }
        super.setMode(mode);
    }
}
